<?php
use Base\AdminController;
use Illuminate\Support\Str;
use JetBrains\PhpStorm\NoReturn;

class ApprovalController extends AdminController
{
    protected string $table = 'approvals';

    protected string $model = "approval";

    #[NoReturn] public function init(): void
    {
        $this->routeWhiteLst = ['approval@getoptions'];
        parent::init();
    }

    #[NoReturn] public function getOptionsAction(): void
    {
        $data = dict('approvals');
        $result = [];
        $class_name = ['blue','purple','red','yellow','green'];
        foreach ($data as $key=>$vo) {
            $flow = FlowModel::query()->where("category_id",$vo)->get()->toArray();
            $field = [];
            foreach ($flow as $k=>$v) {
                $rand_key = array_rand($class_name);
                $flow[$k]['class_name'] = $class_name[$rand_key];
                $form_data = $v['form_data'];
                $rule = [];
                if ($form_data) {
                    foreach ($form_data as $vv) {
                        if ($vv['is_required']) {
                            $rule[$vv['field']] = [
                                [
                                    "required" => true,
                                    "message" => $vv['label'] . "必填",
                                    "trigger" => "blur"
                                ]
                            ];
                        }
                        $field[$vv['field']] = "";
                    }
                }
                $flow[$k]['form_data'] = $form_data;
                $flow[$k]['rules'] = $rule;
                $flow[$k]['field'] = $field;
                $process = $v['data'];
                $process_lst = [];
                if ($process) {
                    if ($process['type'] == 2) {
                        foreach ($process['flow'] as $kk => $vv) {
                            $process_lst[$kk] = [
                                "timestamp" => "",
                                "size" => "large",
                                "type" => "info",
                                "icon" => $vv['type']==1?"Stamp":"Promotion",
                                "content"=>[]
                            ];
                            foreach ($vv['user'] as $item) {
                                $user = UserModel::query()->where("id", $item['user_id'])->first();
                                $process_lst[$kk]['content'][] = [
                                    "nickname" => $user['nickname'],
                                    "avatar" => $user['avatar'],
                                ];
                            }
                        }
                    }
                }
                $flow[$k]['process'] = $process_lst;
            }
            $result[] = [
                'value'=>(int)$vo,
                'label'=>$key,
                'flow'=>$flow
            ];
        }
        $this->apiSuccess($result,"获取成功",20000);
    }

    /**
     * 列表
     * @return void
     */
    #[NoReturn] public function indexAction(): void
    {
        try {
            if (Request::input("is_hid") !== null) {
                $this->where[] = ['is_hid','=',Request::input("is_hid")];
            }
            if (Request::input("flow_id") !== null) {
                $this->where[] = ['flow_id','=',Request::input("flow_id")];
            }
            $status  = match (Request::input("status"))
            {
                "pending"=>0,
                "success"=>1,
                "rejected"=>2,
                default => '',
            };
            $sql = ApprovalModel::query()
                ->join("users","users.id","=","approvals.user_id")
                ->join("organizations","organizations.id","=","approvals.org_id")
                ->join("flows","flows.id","=","approvals.flow_id")
                ->with(["user"=>function ($query) {
                    $query->selectRaw("nickname,avatar")->orderBy("step_order","asc");
                }])
                ->when($status,function ($query,$status) {
                    $query->where("approvals.status",$status);
                })
                ->where("approvals.user_id",$this->member_id)
                ->selectRaw("ws_approvals.*,ws_users.nickname,ws_users.avatar,
                ws_organizations.title as org_name,ws_flows.title as flow_name")
                ->where($this->where)
                ->when($this->whereIn,function ($query,$value){
                    foreach ($value as $item) {
                        $query->whereIn($item[0], $item[1]);
                    }
                });
            if (Request::input("time")) {
                if (is_array(Request::input("time"))) {
                    $sql->whereBetween("created_at",Request::input("time"));
                }else {
                    $sql->whereDate("created_at",Request::input("time"));
                }
            }
            $data = $sql->orderBy("id","desc")
                ->paginate(Request::input("limit",10),['*'],NULL,Request::input("p",1));
            $res = collect($data->items())->toArray();
            foreach ($res as $key=>$vo) {
                $res[$key]['status_d'] = ApprovalModel::$statusMap[$vo['status']];
                $res[$key]['status_color']  = match ($vo['status'])
                {
                    0=>"primary",
                    1=>"success",
                    2=>"danger",
                    -1=>"info",
                    default => 'primary',
                };
                if ($vo['user']) {
                    $res[$key]['approved_by'] = implode(";", array_column($vo['user'], 'nickname'));
                }else {
					$res[$key]['approved_by'] = "--";
				}
                unset($res[$key]['user']);
            }
            $result = [
                'items' => $res,
                'total'=>$data->total(),
                'per_page' => $data->perPage(),
                'page' => $data->currentPage()
            ];
            $this->apiSuccess($result,"获取成功",20000);
        }catch (Exception $exception) {
            Log::$customFileName = LOG_PATH."/errors/";
            Log::error($exception->getMessage().$exception->getTraceAsString());
            $this->apiError($exception->getMessage());
        }
    }

    /**
     * 修改
     * @return void
     */
    protected function update(): void
    {
        DB::beginTransaction();
        try {
            $params  = Request::all();
            $extra = [];
            if (Request::input("id") !== null) $this->apiError("已提交审批，无法修改");
            $flow = FlowModel::query()->where("id",$params['flow_id'])->first();
            if (!$flow) $this->apiError("流程不存在,请重新选择审批项目或联系管理员");
            $type_d = '';
            foreach ($flow['form_data'] as $vo) {
                if ($vo['type'] =='select' &&$vo['options']) {
                    foreach ($vo['options'] as $item) {
                        if ($item['value'] == $params['type']) {
                            $type_d = $item['label'];
                        }
                    }
                }
                if (!DB::schema()->hasColumn($this->table, $vo["field"])) {
                    $extra[] =  [
                        'value' => $params[$vo["field"]],
                        'field' => $vo['field'],
                        'label' => $vo['label'],
                        'data'=>[
                            $vo["field"]=>$params[$vo["field"]]
                        ]
                    ];
                }
            }
            $approval = [
                'uuid' => (string)Str::uuid(),
                'org_id' => $this->org['id'],
                'user_id' => $this->member_id,
                'flow_id' => $params['flow_id'],
                'title' => $flow['title']."-".$type_d."申请",
                'type'=> $params['type']??"",
                'type_name'=>$type_d??"",
                'reason' => $params['reason']??"",
                'start_time'=>$params['start_time']??date("Y-m-d H:i:s"),
                "end_time"=>$params['end_time']??date("Y-m-d H:i:s",strtotime("+7 day")),
                "address"=>$params['address']??"",
                'created_at' => date("Y-m-d H:i:s"),
                'extra'=>json_encode($extra)
            ];
            $res =  App::make($this->getModelMame())->insertGetId($approval);
            if ($flow['data']) {
                $insert = [];
                $cc_record = [];
                $do_task = [];
                if ($flow['data']['type'] == 2) {
                    foreach ($flow['data']['flow'] as $vo) {
                        if ($vo['type']==2) {
                            foreach ($vo['user'] as $vv) {
                                $cc_record[] = [
                                    'approval_id' => $res,
                                    'recipient_id' => $vv['user_id'],
                                    'created_at' => date("Y-m-d H:i:s"),
                                ];
                            }
                        }else {
                            foreach ($vo['user'] as $vv) {
                                $insert[] = [
                                    'approval_id' => $res,
                                    'type' => $vo['type'],
                                    'step_order' => $vo['level'],
                                    'approval_user_id' => $vv['user_id'],
                                    'created_at' => date("Y-m-d H:i:s"),
                                ];
                                if ($vo['type']==1) {
                                    $do_task[] = [
                                        'uuid' => (string)Str::uuid(),
                                        'title' => $approval['title'],
                                        'resource_id' => $res,
                                        'user_id' => $vv['user_id'],
                                        'org_id' => $vv['org_id'],
                                        'review_user_id' => $vv['user_id'],
                                        'urgency' => 4,
                                        'type' => 2,
                                        'data' => json_encode($approval),
                                        'end_time' => $approval['end_time'],
                                        'created_at' => date("Y-m-d H:i:s"),
                                    ];
                                }
                            }
                        }

                    }
                }
                ApprovalFlowModel::insert($insert);
                ApprovalCcRecordModel::insert($cc_record);
                DoTaskModel::insert($do_task);
            }
            $info =  App::make($this->getModelMame())->where('id',$res)->first();
            DB::commit();
            $this->apiSuccess( $info->toArray(),"发起成功",20000);

        } catch (Exception $exception) {
            DB::rollBack();
            Log::$customFileName = LOG_PATH."/errors/";
            Log::error($exception->getMessage().$exception->getTraceAsString());
            $this->apiError($exception->getMessage());
        }
    }

    /**
     * 显示
     * @return void
     */
    #[NoReturn] protected function operate(): void
    {
        $info = ApprovalModel::query()
            ->join("users","users.id","=","approvals.user_id")
            ->join("organizations","organizations.id","=","approvals.org_id")
            ->join("flows","flows.id","=","approvals.flow_id")
            ->with(["user"=>function ($query) {
                $query->selectRaw("nickname,avatar")->orderBy("step_order","asc");
            }])
            ->where("approvals.id",Request::input("ids"))
            ->selectRaw("ws_approvals.*,ws_users.nickname,ws_users.avatar,
            ws_organizations.title as org_name,ws_flows.title as flow_name")
            ->where($this->where)->first();
        if (!$info) $this->apiError("数据不存在");
        $info = $info->toArray();
        $flow = ApprovalFlowModel::query()->join("users","users.id","=","approval_flows.approval_user_id")
            ->where("approval_id",$info['id'])
            ->selectRaw("ws_approval_flows.*,ws_users.nickname,ws_users.avatar")
            ->get()->groupBy("step_order")->toArray();
        $ccRecords = ApprovalCcRecordModel::query()
            ->join("users","users.id","=","approval_cc_records.recipient_id")
            ->where("approval_id",$info['id'])
            ->selectRaw("ws_approval_cc_records.*,ws_users.nickname,ws_users.avatar")
            ->get()->toArray();
        $process_lst = [];
        if ($flow) {
            foreach ($flow as $kk => $vv) {
                $t = [
                    "timestamp" => "",
                    "size" => "large",
                    "type" => "info",
                    "icon" => "Stamp",
                    "content"=>[]
                ];
                foreach ($vv as $item) {
                    $t['content'][] = [
                        "nickname" => $item['nickname'],
                        "avatar" => $item['avatar'],
                        'status'=>$item['status'],
                        'comment'=>$item['comment'],
                        'status_d' => ApprovalModel::$statusMap[$item['status']]
                    ];
                    if ($item['status'] >0) {
                        $t['timestamp'] = $item['approve_at'];
                    }
                    if ($t['timestamp']) {
                        $t['timestamp'] = $item['approve_at']." (".$item['comment'].")";
                    }
                    $t['type']  = match ((int)$item['status'])
                    {
                        0=>"info",
                        1=>"success",
                        2=>"danger",
                        default => 'info',
                    };
                }
                $process_lst[] = $t;
            }
        }
        foreach ($ccRecords as  $vo) {
            $t = [
                "timestamp" => "",
                "size" => "large",
                "type" => "info",
                "icon" => "Promotion",
                "content"=>[]
            ];
            $t['content'][] = [
                "nickname" => $vo['nickname'],
                "avatar" => $vo['avatar'],
                'status'=>$vo['status'],
                'status_d' => $vo['status']==0?"未读":"已读",
            ];
            if ($vo['status'] >0) {
                $t['timestamp'] = $vo['notified_at'];
            }
            $t['type']  = match ((int)$vo['status'])
            {
                0=>"info",
                1=>"success",
                default => 'info',
            };
            $process_lst[] = $t;
        }
        $info['flow'] = $process_lst;
        $info['status_d'] = ApprovalModel::$statusMap[$info['status']];
        $info['status_color']  = match (Request::input("status"))
        {
            0=>"primary",
            1=>"success",
            2=>"danger",
            -1=>"info",
            default => 'primary',
        };
        if ($info['user']) {
            $info['approved_by'] = implode(";", array_column($info['user'], 'nickname'));
        }
        $info['extra'] = json_decode($info['extra'],true);
        unset($info['user']);
        $this->apiSuccess($info,"获取成功",20000);
    }

    /**
     * 撤回
     * @return void
     */
    #[NoReturn] public function revokeAction(): void
    {
        $approval = ApprovalModel::query()->where("id",Request::input("ids"))->first();
		if(!$approval) $this->apiError("数据不存在");
        if ($approval['status']>0) $this->apiError("事项已审批，无法撤回");
        DB::beginTransaction();
        try {
            ApprovalModel::where("id",Request::input("ids"))->update([
                "status" => -1,
            ]);
            ApprovalFlowModel::where("approval_id",Request::input("ids"))->delete();
            ApprovalCcRecordModel::where("approval_id",Request::input("ids"))->delete();
            DoTaskModel::where("resource_id",Request::input("ids"))->where("type",2)->delete();
            DB::commit();
            $this->apiSuccess([],"撤回成功",20000);
        }catch (Exception $exception) {
            DB::rollBack();
            Log::$customFileName = LOG_PATH."/errors/";
            Log::error($exception->getMessage().$exception->getTraceAsString());
            $this->apiError($exception->getMessage());
        }
    }

    /**
     * 文件上传
     * @return void
     */
    public function uploadAction():void
    {
        if (Request::instance()->isPost()) {
            $config = [
                'rootPath' => './public/uploads/fileTemp/',
            ];
            if (!is_dir($config['rootPath'])) mkdir($config['rootPath'], 0755, true);
            $upload = new Upload();
            $uploadInfo = $upload->upload();
            if (!$uploadInfo) $this->apiError($upload->getError());
            $url = getRequestHost(). "/" . $config['rootPath'] . $uploadInfo['file']['savepath'] . $uploadInfo['file']['savename'];
            $result = [
                "url" => $url,
                "field" => Request::input("field")
            ];
            $this->apiSuccess($result ,"上传成功",20000);
        }
    }
}
